<template>
	<view class="xt-button" :class="{ 'xt-button-disabled': disabled, 'xt-button-none': loading }">
		<button
			@tap="xtClick"
			style="padding: 0"
			:style="[baseColor, otherStyle, customStyle]"
			:class="[typeClass, `xt-button-size-${size}`]"
			:hover-stop-propagation="hoverStopPropagation"
			:hover-start-time="Number(hoverStartTime)"
			:hover-stay-time="Number(hoverStayTime)"
			:hover-class="!disabled && !loading ? 'xt-button-hover' : ''"
			:form-type="formType"
			:open-type="openType"
			:app-parameter="appParameter"
			:send-message-title="sendMessageTitle"
			:send-message-path="sendMessagePath"
			:send-message-img="sendMessageImg"
			:show-message-card="showMessageCard"
			:lang="lang"
			:data-name="dataName"
			:session-from="sessionFrom"
			:group-id="groupId"
			:guild-id="guildId"
			:public-id="publicId"
			:data-im-id="dataImId"
			:data-im-type="dataImType"
			:data-goods-id="dataGoodsId"
			:data-order-id="dataOrderId"
			:data-biz-line="dataBizLine"
			@getphonenumber="getphonenumber"
			@getuserinfo="getuserinfo"
			@error="error"
			@opensetting="opensetting"
			@launchapp="launchapp"
			@agreeprivacyauthorization="agreeprivacyauthorization"
			@addgroupapp="addgroupapp"
			@chooseaddress="chooseaddress"
			@chooseinvoicetitle="chooseinvoicetitle"
			@subscribe="subscribe"
			@login="login"
			@im="im"
			@contact="contact"
			@chooseavatar="chooseavatar"
		>
			<view class="xt-button-main">
				<!-- 前置内容 -->
				<view class="xt-button-prepend" :style="{ fontSize: textSize }">
					<slot name="prepend"></slot>
				</view>
				<view class="xt-button-body" :style="{ fontSize: textSize, fontWeight: bold ? 'bold' : 'normal' }">
					<!-- 加载状态 -->
					<view class="xt-button-loading" v-if="loading">
						<slot name="loading">
							<view
								class="xt-loading"
								:style="{
									width: textSize,
									height: textSize
								}"
							></view>
						</slot>
					</view>
					<slot>{{ name }}</slot>
				</view>
				<!-- 后置内容 -->
				<view class="xt-button-append" :style="{ fontSize: textSize }">
					<slot name="append"></slot>
				</view>
			</view>
		</button>
	</view>
</template>
<script>
import props from './props.js';
/**
 * Button 按钮
 * @description 本组件提供一个按钮的功能，让开发者开发起来更加得心应手。减少重复的模板代码
 * @tutorial https://ext.dcloud.net.cn/plugin?name=xt-button
 *
 * @property {String}          		name             					按钮名称(默认 按钮)
 * @property {String}         		color            					按钮颜色
 * @property {String}          		type            					按钮内置颜色，primary，success，warning，danger，info (默认 'primary' )
 * @property {Boolean}        	 	disabled         					是否禁用(默认 false)
 * @property {Boolean}        	 	bold         						文字是否加粗(默认 false)
 * @property {Boolean}         		loading          					是否显示加载状态(默认 false)
 * @property {String}          		text             					是否为文字按钮(默认 false)
 * @property {String|Number}        size             					按钮尺寸,也可自定义传入数值, large，default，small，mini (默认 'default' )
 * @property {Boolean}         		plain            					是否镂空(默认 false)
 * @property {Boolean}         		stop            					是否阻止事件冒泡(默认 false)
 * @property {Boolean}         		round            					圆角按钮(默认 false)
 * @property {Object}         		customStyle            				自定义样式
 * @property {Number}				throttleTime						节流时间,单位ms(默认 0)
 * @property {Boolean}				hoverStopPropagation				指定是否阻止本节点的祖先节点出现点击态，微信小程序有效(默认 true)
 * @property {String | Number}		hoverStartTime						按住后多久出现点击态，单位毫秒(默认 0)
 * @property {String | Number}		hoverStayTime						手指松开后点击态保留时间，单位毫秒(默认 200 )
 * @property {String}          		formType          					用于 <form> 组件，点击分别会触发 <form> 组件的 submit/reset 事件
 * @property {String}          		openType         					开放能力,同uniapp官网
 * @property {String}          		appParameter     					打开 APP 时，向 APP 传递的参数，open-type=launchApp时有效
 * @property {String}				sendMessageTitle					会话内消息卡片标题，openType="contact"时有效
 * @property {String}				sendMessagePath						会话内消息卡片点击跳转小程序路径，openType="contact"时有效
 * @property {String}				sendMessageImg						会话内消息卡片图片，openType="contact"时有效
 * @property {Boolean}				showMessageCard						是否显示会话内消息卡片，设置此参数为 true，用户进入客服会话会在右下角显示"可能要发送的小程序"提示，用户点击后可以快速发送小程序消息，open-type="contact"时有效（默认false）
 * @property {String}				dataName							额外传参参数，用于小程序的data-xxx属性，通过target.dataset.name获取
 * @property {String}				lang								指定返回用户信息的语言，zh_CN 简体中文，zh_TW 繁体中文，en 英文（默认 en ）
 * @property {String}				sessionFrom							会话来源，openType="contact"时有效
 * @property {String}				groupId								打开群资料卡时，传递的群号
 * @property {String}				guildId								打开频道页面时，传递的频道号
 * @property {String}				publicId							打开公众号资料卡时，传递的号码
 * @property {String}				dataImId							客服的抖音号
 * @property {String}				dataImType							IM卡片类型
 * @property {String}				dataGoodsId							商品的id，仅支持泛知识课程库和生活服务商品库中的商品
 * @property {String}				dataOrderId							订单的id，仅支持交易2.0订单
 * @property {String}				dataBizLine							商品类型，“1”代表生活服务，“2”代表泛知识。
 * @event {Function}           		click            					点击事件
 * @event {Function}           		getphonenumber            			获取用户手机号回调,open-type="getPhoneNumber"时有效
 * @event {Function}           		getuserinfo            				用户点击该按钮时，会返回获取到的用户信息，从返回参数的detail中获取到的值同uni.getUserInfo,open-type="getUserInfo"时有效
 * @event {Function}           		error            					当使用开放能力时，发生错误的回调
 * @event {Function}           		opensetting            				在打开授权设置页并关闭后回调
 * @event {Function}           		launchapp            				从小程序打开 App 成功的回调
 * @event {Function}           		agreeprivacyauthorization           用户同意隐私协议事件回调，open-type="agreePrivacyAuthorization"时有效
 * @event {Function}           		addgroupapp            				添加群应用的回调
 * @event {Function}           		chooseaddress            			调起用户编辑并选择收货地址的回调
 * @event {Function}           		chooseinvoicetitle            		用户选择发票抬头的回调
 * @event {Function}           		subscribe            				订阅消息授权回调
 * @event {Function}           		login            					登录回调
 * @event {Function}           		im            						监听跳转IM的成功回调
 * @event {Function}           		contact            					客服消息回调
 * @event {Function}           		chooseavatar            			获取用户头像回调
 * @example <xt-button></xt-button>
 */
export default {
	name: 'xt-button',
	mixins: [props],
	emits: [
		'click',
		'getphonenumber',
		'getuserinfo',
		'error',
		'opensetting',
		'launchapp',
		'agreeprivacyauthorization',
		'addgroupapp',
		'chooseaddress',
		'chooseinvoicetitle',
		'subscribe',
		'login',
		'im',
		'contact',
		'chooseavatar'
	],
	data() {
		return {
			typeClass: '',
			textSize: '34rpx',
			timer: null,
			flag: null
		};
	},
	computed: {
		// 自定义颜色
		baseColor() {
			let style = {};

			if (this.color) {
				// 镂空
				style.color = this.plain || this.text ? this.color : 'white';
				// 非镂空
				if (!this.plain && !this.text) {
					style['background-color'] = this.color;
				}
				// 渐变色
				if (this.color.indexOf('gradient') !== -1 && !this.plain) {
					style.backgroundImage = this.color;
					style.borderWidth = 0;
				} else {
					// 非渐变色
					style.borderColor = this.color;
					style.borderWidth = '2rpx';
					style.borderStyle = 'solid';
				}
			}
			return style;
		},
		otherStyle() {
			let style = {};
			if (this.round) {
				style.borderRadius = '88px';
			}
			return style;
		}
	},
	watch: {
		type: {
			immediate: true,
			handler(newVal) {
				if (this.text) {
					this.typeClass = `xt-button-plain-${newVal} xt-button-text`;
					return;
				}
				if (this.plain) {
					this.typeClass = `xt-button-${newVal} xt-button-plain-${newVal}`;
				} else {
					this.typeClass = 'xt-button-' + newVal;
				}
			}
		}
	},
	methods: {
		/**
		 * 节流
		 *
		 * @param {Function} func 回调函数
		 * @param {Number} wait 延时时间
		 * @param {Boolean} immediate 立即执行
		 */
		throttle(func, wait = 500, immediate = true) {
			const that = this;
			if (immediate) {
				if (!that.flag) {
					that.flag = true;
					typeof func === 'function' && func();
					that.timer = setTimeout(() => {
						that.flag = false;
					}, wait);
				}
			} else if (!that.flag) {
				that.flag = true;
				that.timer = setTimeout(() => {
					that.flag = false;
					typeof func === 'function' && func();
				}, wait);
			}
		},
		xtClick(event) {
			if (!this.disabled && !this.loading) {
				this.throttle(() => {
					this.stop && event.stopPropagation();
					this.$emit('click');
				}, this.throttleTime);
			}
		},
		getphonenumber(res) {
			this.$emit('getphonenumber', res);
		},
		getuserinfo(res) {
			this.$emit('getuserinfo', res);
		},
		error(err) {
			this.$emit('error', err);
		},
		opensetting(res) {
			this.$emit('opensetting', res);
		},
		launchapp(res) {
			this.$emit('launchapp', res);
		},
		agreeprivacyauthorization(res) {
			this.$emit('agreeprivacyauthorization', res);
		},
		addgroupapp(res) {
			this.$emit('addgroupapp', res);
		},
		chooseaddress(res) {
			this.$emit('chooseaddress', res);
		},
		chooseinvoicetitle(res) {
			this.$emit('chooseinvoicetitle', res);
		},
		subscribe(res) {
			this.$emit('subscribe', res);
		},
		login(res) {
			this.$emit('login', res);
		},
		im(res) {
			this.$emit('im', res);
		},
		contact(res) {
			this.$emit('contact', res);
		},
		chooseavatar(res) {
			this.$emit('chooseavatar', res);
		},
		handlePixel(value = 'auto', unit = 'px', count, type) {
			const regular = /^[\+-]?(\d+\.?\d*|\.\d+|\d\.\d+e\+\d+)$/;
			const unitRegex = /^(\d+)([a-zA-Z%]+)$/;
			let valueNum = value;
			let valueUnit = unit;
			let countNum = count;
			let countUnit = unit;
			let result = value;
			if (typeof value === 'string' && unitRegex.test(value)) {
				const valueMatch = value.match(unitRegex);
				valueNum = Number(valueMatch[1]); // 数字部分
				result = Number(valueMatch[1]);
				valueUnit = valueMatch[2]; // 单位部分
			}
			if (typeof count === 'string' && unitRegex.test(count)) {
				const countMatch = count.match(unitRegex);
				countNum = Number(countMatch[1]); // 数字部分
				countUnit = countMatch[2]; // 单位部分
			}
			if (valueNum > 0 && countNum > 0) {
				switch (type) {
					case '+':
						result = `${valueNum + countNum}`;
						break;
					case '-':
						result = `${valueNum - countNum}`;
						break;
					case '*':
						result = `${valueNum * countNum}`;
						break;
					case '/':
						result = `${valueNum / countNum}`;
						break;
				}
			}
			return result + valueUnit;
		},
		setTextSize() {
			if (this.size != 'large' && this.size != 'small' && this.size != 'mini' && this.size != 'default') {
				this.textSize = this.handlePixel(this.size);
				return;
			}
			switch (this.size) {
				case 'large':
					this.textSize = '40rpx';
					break;
				case 'small':
					this.textSize = '24rpx';
					break;
				case 'mini':
					this.textSize = '20rpx';
					break;
				default:
					this.textSize = '30rpx';
					break;
			}
		}
	},
	mounted() {
		this.setTextSize();
	}
};
</script>
<style scoped lang="scss">
@import './style.scss';

button::after {
	border: none;
}
</style>
